﻿using BootstrapBlazor.Components;
using BPM.Web.Shared.Data;
using BPM.Web.Shared.Dependencies;
using BPM.Web.Shared.Extensions;
using Microsoft.AspNetCore.Components.Routing;

namespace BPM.Web.Shared.Service;

[Scoped(typeof(ISysMenuService))]
public class SysMenuService : BaseService, ISysMenuService
{
    private readonly IAuthClient _authClient;
    private readonly IMenuClient _menuClient;
    public SysMenuService(IAuthClient authClient, IMenuClient menuClient, ToastService toast) : base(toast)
    {
        _authClient = authClient;
        _menuClient = menuClient;
    }

    public Task<List<AntDesignTreeNode>?> ChangeAsync(string application)
        => QueryAsync<List<AntDesignTreeNode>>(_menuClient.ChangeAsync(new(application)));

    public async Task<IEnumerable<MenuItem>> ChangeMenuAsync(string application)
        => (await QueryAsync<List<AntDesignTreeNode>>(_menuClient.ChangeAsync(new(application))))
            .HasValueFor((x)
                => x.BuildTreeNode().BuildMenuItem<AntDesignTreeNode, long>((x, r) =>
                {
                    r.Id = x.Id.ToString();
                    r.Icon = x.Meta.Icon;
                    r.Text = x.Meta.Title;
                    r.Target = x.Meta.Target;
                    r.Url = x.Path;
                    r.Match = NavLinkMatch.All;
                }));

    public Task<QueryData<MenuOutput>> ListAsync(GetMenuListInput input)
        => QueryAsync(_menuClient.ListAsync(input));

    public async Task<IEnumerable<CascaderItem>> GetCascaderMenusAsync(string? application)
        => (await QueryAsync<List<MenuTreeOutput>>(_menuClient.TreeAsync(new(application))))
            .BuildCascader<MenuTreeOutput, long>((x, r) =>
            {
                r.Value = x.Id.ToString();
                r.Text = x.Title ?? string.Empty;
            });

    public Task<bool> AddAsync(MenuOutput input)
        => ExecuteAsync(_menuClient.AddAsync(input.Adapt<AddMenuInput>()));

    public Task<bool> DeleteAsync(IEnumerable<MenuOutput> input)
        => DeleteAsync(input.Adapts<MenuOutput, DeleteMenuInput>().Select(x => _menuClient.DeleteAsync(x)));

    public Task<bool> EditAsync(MenuOutput input)
        => ExecuteAsync(_menuClient.EditAsync(input.Adapt<UpdateMenuInput>()));

    public Task<SysMenu?> DetailAsync(QueryMenuInput input)
        => QueryAsync(_menuClient.DetailAsync(input));

    /// <summary>
    /// 获取当前用户所有菜单
    /// </summary>
    /// <returns></returns>
    public async Task<List<MenuItem>> GetCurrentUserMenusAsync(IEnumerable<AppOutput>? apps)
    {
        var result = new List<MenuItem>();
        if (apps !=null)
        {
            foreach (var app in apps)
            {
                var root = new MenuItem()
                {
                    Id =$"app_{app.Id}",
                    Icon = app.Icon,
                    Text = app.Name
                };

                if (!string.IsNullOrEmpty(app.Code))
                {
                    var menus = await QueryAsync<List<AntDesignTreeNode>>(_menuClient.ChangeAsync(new(app.Code)));
                    if (menus?.Count > 0)
                    {
                        var ids = menus.Select(x => x.Id);
                        var pIds = menus.Select(x => x.Pid);
                        var rIds = pIds.Except(ids);//差集即为根节点
                        if (rIds != null)
                        {
                            foreach (var rId in rIds)
                            {
                                BuildChildMenus(menus, root, rId);
                            }
                        }
                    }
                }
                result.Add(root);
            }
        }

        return result;
    }

    /// <summary>
    /// 构造子节点集合
    /// </summary>
    /// <param name="nodes">所有菜单节点</param>
    /// <param name="parent">上级菜单</param>
    /// <param name="pId">上级菜单编号</param>
    private static void BuildChildMenus(IEnumerable<AntDesignTreeNode> nodes, MenuItem parent, long pId)
    {
        var children = nodes.Where(x => x.Pid == pId);
        if (children != null)
        {
            var menus = new List<MenuItem>();
            foreach (var child in children)
            {
                var menu = new MenuItem()
                {
                    ParentId = parent.Id,
                    Id = $"menu_{child.Id}",
                    Text = child.Meta.Title,
                    Icon = child.Meta.Icon,
                    Url = child.Path,
                };
                menus.Add(menu);
                BuildChildMenus(nodes, menu, child.Id);
            }
            parent.Items = menus;
        }
        else
        {
            parent.Items = Enumerable.Empty<MenuItem>();
        }
    }
}

